﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;

namespace Axe
{
    public static partial class Utility
    {
        #region public static bool IsValidIP(string text)
        public static bool IsValidIP(string text)
        {
            bool valid = true;

            IPMatch(text, IPAddress.None, ref valid);

            return valid;
        } 
        #endregion

        #region public static bool IPMatch(string val, IPAddress ip)
        public static bool IPMatch(string val, IPAddress ip)
        {
            bool valid = true;

            return IPMatch(val, ip, ref valid);
        } 
        #endregion

        #region public static bool IPMatchCIDR(string cidr, IPAddress ip)
        public static bool IPMatchCIDR(string cidr, IPAddress ip)
        {
            string[] str = cidr.Split('/');

            if (str.Length < 2)
                return false;

            IPAddress cidrPrefix;

            if (!IPAddress.TryParse(str[0], out cidrPrefix))
                return false;

            int cidrLength = Utility.ToInt32(str[1]);

            return IPMatchCIDR(cidrPrefix, ip, cidrLength);
        } 
        #endregion

        #region public static bool IPMatchCIDR(IPAddress cidrPrefix, IPAddress ip, int cidrLength)
        public static bool IPMatchCIDR(IPAddress cidrPrefix, IPAddress ip, int cidrLength)
        {
            if (cidrPrefix == null || ip == null)
                return false;

            if (cidrLength <= 0 || cidrLength >= 32)   //if invalid cidr Length, just compare IPs
                return ip.Equals(cidrPrefix);

            uint mask = uint.MaxValue << cidrLength;

            long cidrValue = Utility.GetLongAddressValue(cidrPrefix);
            long ipValue = Utility.GetLongAddressValue(ip);

            return ((cidrValue & mask) == (ipValue & mask));
        } 
        #endregion

        #region public static bool IPMatch(string val, IPAddress ip, ref bool valid)
        public static bool IPMatch(string val, IPAddress ip, ref bool valid)
        {
            if (val == null || ip == null)
            {
                valid = false;
                return false;
            }

            valid = true;

            string[] split = val.Split('.');

            for (int i = 0; i < 4; ++i)
            {
                int lowPart, highPart;

                if (i >= split.Length)
                {
                    lowPart = 0;
                    highPart = 255;
                }
                else
                {
                    string pattern = split[i];

                    if (pattern == "*")
                    {
                        lowPart = 0;
                        highPart = 255;
                    }
                    else
                    {
                        lowPart = 0;
                        highPart = 0;

                        bool highOnly = false;
                        int lowBase = 10;
                        int highBase = 10;

                        for (int j = 0; j < pattern.Length; ++j)
                        {
                            char c = (char)pattern[j];

                            if (c == '?')
                            {
                                if (!highOnly)
                                {
                                    lowPart *= lowBase;
                                    lowPart += 0;
                                }

                                highPart *= highBase;
                                highPart += highBase - 1;
                            }
                            else if (c == '-')
                            {
                                highOnly = true;
                                highPart = 0;
                            }
                            else if (c == 'x' || c == 'X')
                            {
                                lowBase = 16;
                                highBase = 16;
                            }
                            else if (c >= '0' && c <= '9')
                            {
                                int offset = c - '0';

                                if (!highOnly)
                                {
                                    lowPart *= lowBase;
                                    lowPart += offset;
                                }

                                highPart *= highBase;
                                highPart += offset;
                            }
                            else if (c >= 'a' && c <= 'f')
                            {
                                int offset = 10 + (c - 'a');

                                if (!highOnly)
                                {
                                    lowPart *= lowBase;
                                    lowPart += offset;
                                }

                                highPart *= highBase;
                                highPart += offset;
                            }
                            else if (c >= 'A' && c <= 'F')
                            {
                                int offset = 10 + (c - 'A');

                                if (!highOnly)
                                {
                                    lowPart *= lowBase;
                                    lowPart += offset;
                                }

                                highPart *= highBase;
                                highPart += offset;
                            }
                            else
                            {
                                valid = false;
                            }
                        }
                    }
                }

                int b = (byte)(Utility.GetAddressValue(ip) >> (i * 8));

                if (b < lowPart || b > highPart)
                    return false;
            }

            return true;
        }
        #endregion

        #region public static bool IPMatchClassC(IPAddress ip1, IPAddress ip2)
        public static bool IPMatchClassC(IPAddress ip1, IPAddress ip2)
        {
            return ((Utility.GetAddressValue(ip1) & 0xFFFFFF) == (Utility.GetAddressValue(ip2) & 0xFFFFFF));
        } 
        #endregion

        #region public static int GetAddressValue(IPAddress address)
        public static int GetAddressValue(IPAddress address)
        {
            if (address == null)
                return 0;

#pragma warning disable 618
            return (int)address.Address;
#pragma warning restore 618
        }

        public static long GetLongAddressValue(IPAddress address)
        {
            if (address == null)
                return 0;

#pragma warning disable 618
            return address.Address;
#pragma warning restore 618
        } 
        #endregion
    }
}
